package OOPAndMultiThreadArchiveManager.Server.Controllers;

import OOPAndMultiThreadArchiveManager.Server.Entities.Archive;
import OOPAndMultiThreadArchiveManager.Server.Entities.DbContext;
import OOPAndMultiThreadArchiveManager.Server.Entities.UserInfo;
import OOPAndMultiThreadArchiveManager.Server.Models.ApiReceive;
import OOPAndMultiThreadArchiveManager.Server.Tools.PropertiesLoader;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.io.*;
import java.net.Socket;
import java.util.List;

public class FileDownloadController extends Thread {
    private final Socket socket;
    private final OutputStream stream;
    private static final ObjectMapper objectMapper = new ObjectMapper();
    private final DbContext dbContext = new DbContext();
    private String saveFilesPath = "";

    public FileDownloadController(Socket socket) throws IOException {
        saveFilesPath = PropertiesLoader.SaveFilesPath;
        this.socket = socket;
        stream = socket.getOutputStream();
    }

    @Override
    public void run() {
        try {
            var inputStream = new DataInputStream(socket.getInputStream());
            var byteArrayOutputStream = new ByteArrayOutputStream();
            var bytes = new byte[2048];
            var n = 0;
            while ((n = inputStream.read(bytes)) != -1) {
                byteArrayOutputStream.write(bytes, 0, n);
            }
            var stringInputStream = byteArrayOutputStream.toString();
            socket.shutdownInput();

            ApiReceive receive = objectMapper.readerFor(ApiReceive.class).readValue(stringInputStream);
            byteArrayOutputStream.close();

            if (receive.api != ApiReceive.Api.GET_Archive) {
                socket.close();
                return;
            }

            var userList = dbContext.select(
                    new UserInfo(receive.user.name, receive.user.password, null),
                    List.of("user","password"));
            if (userList.isEmpty()) {
                socket.close();
                return;
            }

            var archive = objectMapper.convertValue(receive.data, Archive.class);
            if (dbContext.select(archive, List.of("hashCode", "fileName", "description", "dateTime", "uploader")).isEmpty()) {
                socket.close();
                return;
            }

            var fileInputStream = new FileInputStream(saveFilesPath + archive.fileName);

            var length = 0;
            var outBytes = new byte[1024];
            while ((length = fileInputStream.read(outBytes)) != -1) {
                stream.write(outBytes, 0, length);
            }
            fileInputStream.close();
            stream.flush();
            stream.close();
            socket.close();
        } catch (IOException e) {
            try {
                socket.close();
            } catch (IOException ex) {
                throw new RuntimeException(ex);
            }
        }
    }
}